package dataProcess;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import jxl.Workbook;
import jxl.Sheet;
import jxl.Cell;
import org.ejml.data.DenseMatrix64F;
import org.ejml.ops.CommonOps;
import org.ejml.ops.MatrixIO;

import ds.BugInfo;
import dataProcess.StringSpliter;

public class ReadExcel {

	
	public static void main(String args[]){
		String[] category = {"Function", "Security", "Usability", "UI"};
		ArrayList<BugInfo> allBugs = 	getAndroidBugs("data/input/BugReports-20121231-200618.xls");
		//ArrayList<BugInfo> allBugs = 	getAllBugs("data/input/BugReports-20121231-200618.xls");
		HashMap<String, String> bugId2Class = getGroundTruth(allBugs);
		//bug2TextFile(allBugs, "output/allBugs.txt");
		DenseMatrix64F word_category = matrixBuilder("data/input/wvToolTfIdf.txt", bugId2Class);
		//translateToArff("data/input/wvToolTfIdf.txt", "data/input/wvToolWordlist.txt", "output/Micro.arff", bugId2Class);
	}
	
	private static HashMap<String, String> getGroundTruth(ArrayList<BugInfo> allBugs){
		HashMap<String, String> bugId2Class = new HashMap<String, String>();
		for(BugInfo bug : allBugs){
			String bugId = bug.bugID;
			String className = bug.label;
			if(!bugId2Class.containsKey(bugId)){
				bugId2Class.put(bugId, className);
			}
		}
		return bugId2Class;
	}
	
	
	public static ArrayList<BugInfo>  getAllBugs(String fileName){
		ArrayList<BugInfo> allBugs = new ArrayList<BugInfo>();
		int rowCount;
		try{
			Workbook wb = Workbook.getWorkbook(new File(fileName));
			Sheet sheet = wb.getSheet(0);
			rowCount = sheet.getRows();
			StringSpliter ss = StringSpliter.getDefaultSpliter();
			for(int i = 0; i < rowCount; i++){
				String label = sheet.getCell(6, i).getContents();
				if(!label.equals("Functionality") && !label.equals("Security") &&! label.equals("UI") && !label.equals("Usability") )
					continue;
				BugInfo bug = new BugInfo();
				bug.label = label;
				bug.bugID = sheet.getCell(0, i).getContents();
				bug.content = sheet.getCell(10, i).getContents();
				bug.content = ss.simpleSplitSentenceIntoWords(bug.content);
				allBugs.add(bug);
			}		
		}catch(Exception e){
			System.out.println(e.getStackTrace());
		}
		return allBugs;
	}
	/**
	 *Get Android bugs from Excel
	 * @param fileName
	 * @return ArrayList<BugInfo>
	 */
	public static ArrayList<BugInfo>  getAndroidBugs(String fileName){
		ArrayList<BugInfo> allBugs = new ArrayList<BugInfo>();
		ArrayList<BugInfo> funcBugs = new ArrayList<BugInfo>();
		ArrayList<BugInfo> secBugs = new ArrayList<BugInfo>();
		ArrayList<BugInfo> uiBugs = new ArrayList<BugInfo>();
		ArrayList<BugInfo> usaBugs = new ArrayList<BugInfo>();
		int rowCount;
		try{
			Workbook wb = Workbook.getWorkbook(new File(fileName));
			Sheet sheet = wb.getSheet(0);
			rowCount = sheet.getRows();
			StringSpliter ss = StringSpliter.getDefaultSpliter();
			//System.out.print(rowCount + "  " + colCount);
			for(int i = 0; i < rowCount; i++){
				String label = sheet.getCell(6, i).getContents();
				if(!label.equals("Functionality") && !label.equals("Security") &&! label.equals("UI") && !label.equals("Usability") )
					continue;
				BugInfo bug = new BugInfo();
				bug.label = label;
				bug.bugID = sheet.getCell(0, i).getContents();
				bug.content = sheet.getCell(10, i).getContents();
				bug.content = ss.simpleSplitSentenceIntoWords(bug.content);
				if(label.equals("Functionality") && funcBugs.size()<=38)
					funcBugs.add(bug);
				else if(label.equals("Security") && secBugs.size()<=38)
					secBugs.add(bug);
				else if(label.equals("UI") && uiBugs.size()<=38)
					uiBugs.add(bug);
				else if(label.equals("Usability") && usaBugs.size()<=38)
					usaBugs.add(bug);
			}
		} catch(Exception e){
			System.out.println(e.getStackTrace());
		}
		allBugs.addAll(secBugs);
		allBugs.addAll(funcBugs);
		allBugs.addAll(usaBugs);
		allBugs.addAll(uiBugs);
		return allBugs;
	}

	/**
	 * a line is a bug
	 * @param bugs
	 */
	public static void bug2TextFile(ArrayList<BugInfo> bugs, String fileName){
		try {
			FileWriter fw = new FileWriter(fileName);
			fw.write(bugs.size()+"\n");
			for(int i=0; i<bugs.size(); i++){
				BugInfo bug = bugs.get(i);
				String line = bug.bugID + " " + bug.content + "\n";
				fw.write(line);
			}
			fw.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}

	public static int[] readSummaryInfo(String summaryInfo) {
		String[] pairs = summaryInfo.split(" ");
		int[] values = new int[pairs.length];
		for(int i = 0; i < values.length; i++){
			String[] pair = pairs[i].split(":");
			values[i] = Integer.parseInt(pair[1]);
		}
		return values;
	}
	
	/**
	 * prepare weka data
	 * @param bugReports
	 * @param vsmTfidffile
	 * @param vsmWordlistfile
	 * @param arffFile
	 */
	protected static void translateToArff(String vsmTfidffile, String vsmWordlistfile,String arffFile, HashMap<String, String> bugId2Class) {
		
		BufferedReader tfidfReader = null;
		PrintStream arffStream = null;
		try {
			tfidfReader = new BufferedReader(new FileReader(vsmTfidffile));
			arffStream = new PrintStream(arffFile);
		
			String summary = tfidfReader.readLine();
			int[] values = readSummaryInfo(summary);
			int wordnum = values[0];
			int bugCount = values[1] + values[2];
			List<String> wordList = readWordList(vsmWordlistfile, wordnum);
			
			printAttributes(arffStream, wordList);
			
			for(int count = 0; count< bugCount; count++) {
				String tfidfLine = tfidfReader.readLine();
				String[]  trainUnits= tfidfLine.split(";");
				String bugId = trainUnits[0];
				
				if(trainUnits.length < 2) {
					System.out.println("ERROR: in line " + count);
					continue;
				}
				String className = bugId2Class.get(bugId);
				
				if(className == null){
					System.out.println("ERROR: " + bugId);
					continue;
				}
			
				arffStream.print("{");
				arffStream.print("0 " + className);
				String[] tfidfPairs = trainUnits[1].trim().split(" ");
				for(int i = 0; i < tfidfPairs.length; i++){
					String[] pair = tfidfPairs[i].split(":");
					int attributeIndex = Integer.parseInt(pair[0]) + 1;
					double value = Double.parseDouble(pair[1]);					
					arffStream.print(", " + attributeIndex + " " + value);
				}
				arffStream.println("}");
			}
		} catch (NumberFormatException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				tfidfReader.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	private static void printAttributes(PrintStream arffStream, List<String> wordList) {
		arffStream.println("@relation BugReports");
		String[] kind = {"Functionality", "Security", "Usability","UI"};
		arffStream.print("@attribute class {");
		for(int i = 0; i < kind.length-1; i ++){
			arffStream.print(kind[i] + ", ");
		}
		arffStream.print(kind[kind.length-1]);
		arffStream.println("}");
		for(String word : wordList){
			arffStream.println("@attribute " + word + " numeric");
		}
		arffStream.println("@data");
	}

	private static List<String> readWordList(String vsmWordlistfile, int count) {
		List<String> wordList = new ArrayList<String>();
		BufferedReader wordReader = null;
		try {
			wordReader = new BufferedReader(new FileReader(vsmWordlistfile));
			for(int i = 0; i < count; i ++){
				String word = wordReader.readLine().trim();
				wordList.add(word);
			}
			
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}finally{
			try {
				wordReader.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return wordList;
	}
	
	/**
	 * get word-label matrix 
	 * @param fileName
	 * @param bugId2Class
	 * @return
	 */
	private static 	DenseMatrix64F matrixBuilder(String fileName, HashMap<String, String> bugId2Class){
		try {
			HashMap<String, Integer> label2index = new HashMap<String, Integer>();
			label2index.put("Functionality", 0);
			label2index.put("Security", 1);
			label2index.put("Usability", 2);
			label2index.put("UI", 3);
			
			BufferedReader br =  new BufferedReader(new FileReader(fileName));
			String summery = br.readLine();
			String[] units = summery.split(" ");
			int wordCount = Integer.parseInt(units[0].split(":")[1]);
			int trainBugCount = Integer.parseInt(units[1].split(":")[1]);
			int testBugCount = Integer.parseInt(units[2].split(":")[1]);
			DenseMatrix64F result = new DenseMatrix64F(wordCount, 4);
			//construct matrix		
			for(int i = 0; i < trainBugCount; i++ ){
				String wordVector = br.readLine();
				String[] words = wordVector.split(" ");
				String bugId = words[0].substring(0, words[0].length()-1);
				String label = bugId2Class.get(bugId);
				int classIndex = label2index.get(label);
				for(int j=1; j<words.length; j++){
					int wordIndex = Integer.parseInt(words[j].split(":")[0]);
					result.set(wordIndex, classIndex, result.get(wordIndex, classIndex)+1);
				}
			}
			PrintStream ps0 = new PrintStream("output/matrix_0.txt");
			MatrixIO.print(ps0, result, 10, 8);
			DenseMatrix64F rowSum = new DenseMatrix64F(result.numRows, 1);
			CommonOps.sumRows(result, rowSum);
			for(int row=0; row<result.numRows;row++)
				for(int col = 0; col<result.numCols; col++){
					if(rowSum.get(row, 0) !=0)
						result.set(row, col, result.get(row, col)/rowSum.get(row, 0));
				}
			PrintStream ps = new PrintStream("output/matrix.txt");
			MatrixIO.print(ps, result, 10, 8);
			//test
			int correctNum=0;
			int[] record = new int [result.numCols];
			for(int x=0; x<record.length; x++){
				record[x] = 0;		
			}
			for(int i=0; i<testBugCount; i++){
				String tsetVector = br.readLine();
				String[] testWords = tsetVector.split(" ");
				String bugId = testWords[0].substring(0, testWords[0].length()-1);
				int realCateIndex = label2index.get(bugId2Class.get(bugId));
				
				
				double[] p = new double[result.numCols];
				for(int x=0; x<p.length; x++){
					p[x] = 0;			
				}
				for(int col = 0; col<result.numCols; col++){
					for(int j=1; j<testWords.length; j++){
						int wordIndex = Integer.parseInt(testWords[j].split(":")[0]);
						p[col] = p[col] + result.get(wordIndex, col);
					}
				}
				
				int myCateIndex = 0;
				double pMAX = 0;
				for(int x=0; x<p.length; x++){
					if(p[x] >= pMAX){
						pMAX = p[x];
						myCateIndex = x;
					}				
				}
				if(realCateIndex == myCateIndex){
					correctNum++;
					record[realCateIndex]++;
				}
			}
			br.close();
			System.out.println("total:"+(double)correctNum*100/testBugCount + "%");
			System.out.println("0:"+(double)record[0]*100/8 + "%");
			System.out.println("1:"+(double)record[1]*100/4 + "%");
			System.out.println("2:"+(double)record[2]*100/8 + "%");
			System.out.println("3:"+(double)record[3]*100/8 + "%");
			return result;
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
		
	}
	

}




